/*:
* @plugindesc (v1.11)TP核心-双MP系统
* @author 小c
* @version 1.10
* @date 1/4/2020
*
* @param Default Max TP Value
* @text 默认TP上限
* @type number
* @min 0
* @desc 当上限公式执行失败时取此值
* @default 100
*
* @param Default Max TP Formula
* @text 默认TP上限公式
* @type note
* @desc 默认TP公式，user为当前角色，对没有任何标签的目标执行此公式
* @default "//变量user为当前角色或敌人，tp为TP上限取值\nif(user.isActor())\n    tp = user.level * 3;\nelse\n    tp = 100;"
*
* @param TP Default All
* @text 默认TP全满
* @type boolean
* @on 全满
* @off 不全满
* @default true
* @desc 若此项为true，必定保留TP
* 如果执行升级恢复，此项为true时升级将回满TP
*
* @param TP Preserved
* @text 是否保留TP
* @type boolean
* @on 保留
* @off 不保留
* @default true
*
* @param Init TP Formula
* @text 战斗初始TP公式
* @default Math.randomInt(this.maxTp() / 4)
* @desc 当TP不保留时生效，战斗初始TP的自定义公式
* 
* @param Damage Image Lines
* @text 伤害数字总行数
* @type number
* @min 1
* @desc 伤害图总行数
* @default 5
*
* @param TP Popup Base Line
* @text TP伤害基准行
* @type number
* @min 0
* @default 0
*
* @param Gain TP From Damage
* @text 受伤时获得TP
* @type boolean
* @on 获取
* @off 不获取
* @default false
*
* @param TP Recover Variance
* @text TP伤害默认散度
* @type number
* @min 0
* @max 100
* @default 20
* @desc TP技能的默认散度，当没有配置TP散度且技能也没有伤害时取此值。
*
* @param TP Recover Critical
* @text TP效果默认暴击
* @type boolean
* @on 暴击
* @off 不暴击
* @desc TP技能默认是否暴击，当没有配置TP暴击且技能也没有伤害时取此值。
* @default true
*
* @help
* 轩辕剑命灵体系统，将TP转换为MP体系。
* 注意：将该插件放在YEP战斗核心以及暴击控制的下面。
* 若更新至1.11版以上且你在别处引用了TPManager的静态成员，请加上CP前缀
* 1.11版已经取消TPManager，修改为CP.TPManager
* 若你由旧版升级至1.11版或以上，请执行以下操作：
* 打开插件管理器的CP_TPCore，确定，保存工程。
* 如果你只替换JS文件而不执行上面的操作，会导致参数错误，使整个插件失
* 效。
* 
* 插件参数说明
* 默认TP全满：人物初始化时TP是否满值，若为true，执行完全恢复时TP也恢复。
* 此项为true时，【是否保留TP】必然是true
* 
* 是否保留TP：若true，战斗开始不重置TP，若false，保留默认效果。
* 默认效果是否保留TP由【特征】-【其他】-【特殊标志】-【保留TP】决定。
* 
* TP伤害基准行
* 参考img/system/damage.png，图片从上到下分多行，顶端称为第0行。
* 默认为
* 0行：HP伤害
* 1行：HP恢复
* 2行：MP伤害
* 3行：MP恢复
* 4行：miss
* 可在miss下方扩展数值用于TP伤害与恢复。
* 若此参数为x，则x行用于TP伤害，(x+1)行用于TP恢复。
* 在设置此参数的同时，务必将伤害数字总行数同时指定。
*
* 插件主要用途
* 1. TP上限
* 角色、职业、敌人标签
* <TP Value: x>
* 指定TP上限为固定值x
*
* <TP Formula Eval>
* // JavaScript code
* tp = user.level * 10;
* </TP Formula Eval>
* TP上限公式 user表示当前角色，tp的取值即为上限值。
*
* 2. TP恢复或TP伤害
* 技能、物品标签
* <TP Recover Percent: x>
* 执行恢复TP 百分之x，x取值[0, 100]。
* <TP Recover Value: x>
* 执行恢复TP x点。
*
* <TP Damage Percent: x>
* 执行伤害TP 百分之x，x取值[0, 100]。
* <TP Damage Value: x>
* 执行伤害TP x点。
*
* 这四个标签中，Recover Percent与Recover Value可同时出现，Damage Percent与
* Damage Value可同时出现。
* 举例：
* <TP Recover Percent: 10>
* <TP Recover Value: 30>
* 假设张三的TP上限为200，此物品的基础恢复为50【200×0.1+30】点。
* <TP Variance: x> TP技能物品的分散度为x，取值[0, 100]
* 若没有标签，且技能伤害中有HP或MP效果，TP分散度与伤害分散度一致。
* 若没有标签，且技能伤害类型为无，分散度以插件参数为准。
*
* <TP Recover Eval>
* // JavaScript code
* value = user.mat / 10 + target.maxTp() / 20;
* variance = 25;
* </TP Recover Eval>
* TP恢复公式，user为技能使用者，target为技能目标。
* variance为效果分散度，可忽略。
*
* <TP Damage Eval>
* // JavaScript code
* value = user.atk - target.def;
* variance = 30;
* </TP Damage Eval>
* TP伤害公式，变量说明与恢复相同。
*
* TP伤害暴击
* <TP Critical> TP伤害可暴击
* <TP Not Critical> TP伤害不可暴击
* 若无此标签，以技能伤害设置为准，技能无伤害则以插件参数为准。
*
* TP逆转：即有此效果的人执行恢复TP时转换为指定比例的TP伤害
* 角色/职业/武器/防具/敌人/状态标签
* <TP Reverse Rate: x>
* 设置TP逆转效果比率为x，x>0且为小数，无上限
* 例子：<TP Reverse Rate: 0.1>
* 此效果将TP恢复逆转为原效果10%的TP伤害
* 注意：
* 1. 当有多个TP逆转效果叠加时，所有效果以加法叠加
* 2. 若x为负值，此单项无效
*
* 3. TP上限【由人物特性决定】
* 角色、职业、武器、防具、敌人、状态标签
* <TP Rate: x> TP上限比率为x
* 当x=1.1时相当于MV特性中的【最大HP * 110%】。
*
* <TP Rate Eval>
* // JavaScript code
* rate = user.level / 10 + 1;
* </TP Rate Eval>
* 用公式计算比率，user为当前角色。
*
* <TP Plus: x> TP上限增加x。
* x=20相当于装备基础属性中的【最大HP: 20】。
*
* <TP Plus Eval>
* // JavaScript code
* plus = user.level + 1;
* </TP Plus Eval>
* 用公式计算增加参数，user为当前角色。
*
* 4. TP永久提升【上限药品、事件】
* 物品标签
* <Add TP Param: x>
* 使用该物品永久增加TP上限x。
*
* 插件指令
* ChangeMaxTp actorId value
* 改变指定角色的TP上限
* 例：ChangeMaxTp 1 +100
* 增加1号角色TP上限100点。
*
* <Add TP Param Eval>
* // JavaScript code
* plus = user.atk;
* </Add TP Param Eval>
* 用公式计算增加参数，user为当前角色。
*
* 5. TP技能消耗比率
* 技能消耗TP比率 比如【TP消耗-10%】等。
* 角色、职业、武器、防具、敌人、状态标签
* <TP Cost Rate: x>
* TP消耗比率为x，x=0.9表示消耗减少10%。
* 
* <TP Cost Rate Eval>
* // JavaScript code
* rate = 1 - user.level / 100;
* </TP Cost Rate Eval>
* 用公式计算比率，user为当前角色。
*
* 注：预留JavaScript函数
* battler.maxTp() 返回战斗这的tp上限
* battler.addTPParam(value) 增加战斗者tp上限value 
*
* action.isTpEffect() 行动是否为TP效果
* action.isTpDamage() 行动是否为TP伤害
* action.isTpRecover() 行动是否为TP恢复
*/

var Imported = Imported || {};
Imported.CP_TPCore = true;

var CP = CP || {};
CP.TPManager = CP.TPManager || {};
CP.TPManager.Params = PluginManager.parameters("CP_TPCore");

CP.TPManager.DEFAULT_MAX_TP_VALUE = Number(CP.TPManager.Params["Default Max TP Value"]) || 0;
CP.TPManager.DEFAULT_MAX_TP_FORMULA = JSON.parse(CP.TPManager.Params["Default Max TP Formula"]).trim();

CP.TPManager.TP_DEFAULT_ALL = eval(CP.TPManager.Params["TP Default All"]) || false;
CP.TPManager.TP_PRESERVED = eval(CP.TPManager.Params["TP Preserved"]) || false;
CP.TPManager.INIT_TP_FORMULA = CP.TPManager.Params["Init TP Formula"].trim();

CP.TPManager.TP_POPUP_BASE_LINE = Number(CP.TPManager.Params["TP Popup Base Line"]) || 0;
CP.TPManager.DAMAGE_IMAGE_LINES = Number(CP.TPManager.Params["Damage Image Lines"]) || 0;

CP.TPManager.GAIN_TP_FROM_DAMAGE = eval(CP.TPManager.Params["Gain TP From Damage"]);

CP.TPManager.TP_RECOVER_VARIANCE = Number(CP.TPManager.Params["TP Recover Variance"]) || 0;
CP.TPManager.TP_RECOVER_CRITICAL = eval(CP.TPManager.Params["TP Recover Critical"]) || false;

CP.TPManager._loaded = false;
CP.TPManager.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.TPManager.DATABASE_LOADED.call(this))
		return false;

	if(!CP.TPManager._loaded){
		CP.TPManager.loadTPFormula($dataActors);
		CP.TPManager.loadTPFormula($dataClasses);
		CP.TPManager.loadTPFormula($dataEnemies);

		CP.TPManager.loadTPRecovery($dataSkills);
		CP.TPManager.loadTPRecovery($dataItems);

		CP.TPManager.loadTPItemReverse($dataActors);
		CP.TPManager.loadTPItemReverse($dataClasses);
		CP.TPManager.loadTPItemReverse($dataWeapons);
		CP.TPManager.loadTPItemReverse($dataArmors);
		CP.TPManager.loadTPItemReverse($dataEnemies);
		CP.TPManager.loadTPItemReverse($dataStates);

		CP.TPManager.loadTPRateAndPlus($dataActors);
		CP.TPManager.loadTPRateAndPlus($dataClasses);
		CP.TPManager.loadTPRateAndPlus($dataWeapons);
		CP.TPManager.loadTPRateAndPlus($dataArmors);
		CP.TPManager.loadTPRateAndPlus($dataEnemies);
		CP.TPManager.loadTPRateAndPlus($dataStates);

		CP.TPManager.loadTPAddItem();

		CP.TPManager.loadTPCostRate($dataActors);
		CP.TPManager.loadTPCostRate($dataClasses);
		CP.TPManager.loadTPCostRate($dataWeapons);
		CP.TPManager.loadTPCostRate($dataArmors);
		CP.TPManager.loadTPCostRate($dataEnemies);
		CP.TPManager.loadTPCostRate($dataStates);
		CP.TPManager._loaded = true;
	}

	return true;
};

CP.TPManager.loadTPFormula = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];

		item.tpFormula = null;
		item.tpValue = 0;

		if(item.meta["TP Value"]){
			var value = Number(item.meta["TP Value"]) || 0;
			item.tpValue = value;
		}

		if(item.meta["TP Formula Eval"]){
			var reg = /<TP Formula Eval>([\s\S]*)<\/TP Formula Eval>/;
			reg.exec(item.note);
			item.tpFormula = RegExp.$1;
		}
	}
};

CP.TPManager.loadTPRecovery = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];

		item.tpRecover = {};
		item.tpRecover.percent = 0;
		item.tpRecover.value = 0;
		item.tpRecover.type = 0;
		item.tpRecover.eval = null;
		item.tpRecover.critical = item.damage.critical;
		item.tpRecover.variance = item.damage.variance;
		if(item.damage.type === 0){
			item.tpRecover.variance = this.TP_RECOVER_VARIANCE;
			item.tpRecover.critical = this.TP_RECOVER_CRITICAL;
		}

		if(item.meta["TP Recover Percent"]){
			var tprp = Number(item.meta["TP Recover Percent"]);
			item.tpRecover.percent = tprp / 100;
			item.tpRecover.type = 1;
		}

		if(item.meta["TP Recover Value"]){
			var tprv = Number(item.meta["TP Recover Value"]) || 0;
			item.tpRecover.value = tprv;
			if(item.tpRecover.type === 0)
				item.tpRecover.type = 1;
		}

		if(item.meta["TP Recover Eval"]){
			var reg = /<TP Recover Eval>([\s\S]*)<\/TP Recover Eval>/;
			reg.exec(item.note);
			item.tpRecover.eval = RegExp.$1;
			item.tpRecover.type = 1;
		}

		if(item.meta["TP Damage Percent"]){
			var tpdp = Number(item.meta["TP Damage Percent"]);
			item.tpRecover.percent = tpdp / 100;
			item.tpRecover.type = -1;
		}

		if(item.meta["TP Damage Value"]){
			var tpdv = Number(item.meta["TP Damage Value"]) || 0;
			item.tpRecover.value = tpdv;
			if(item.tpRecover.type === 0)
				item.tpRecover.type = -1;
		}

		if(item.meta["TP Damage Eval"]){
			var reg = /<TP Damage Eval>([\s\S]*)<\/TP Damage Eval>/;
			reg.exec(item.note);
			item.tpRecover.eval = RegExp.$1;
			item.tpRecover.type = -1;
		}

		if(item.meta["TP Variance"]){
			var tpv = Number(item.meta["TP Variance"]) || 0;
			item.tpRecover.variance = tpv;
		}

		if(item.meta["TP Critical"])
			item.tpRecover.critical = true;
		if(item.meta["TP Not Critical"])
			item.tpRecover.critical = false;
	}
};

CP.TPManager.loadTPRateAndPlus = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.tpRate = 1;
		item.tpRateEval = null;
		item.tpPlus = 0;
		item.tpPlusEval = null;

		if(item.meta["TP Rate"]){
			var rate = Number(item.meta["TP Rate"]) || 1;
			item.tpRate = rate;
		}

		if(item.meta["TP Rate Eval"]){
			var reg = /<TP Rate Eval>([\s\S]*)<\/TP Rate Eval>/;
			reg.exec(item.note);
			item.tpRateEval = RegExp.$1;
		}

		if(item.meta["TP Plus"]){
			var plus = Number(item.meta["TP Plus"]) || 0;
			item.tpPlus = plus;
		}

		if(item.meta["TP Plus Eval"]){
			var reg = /<TP Plus Eval>([\s\S]*)<\/TP Plus Eval>/;
			reg.exec(item.note);
			item.tpPlusEval = RegExp.$1;
		}
	}
};

CP.TPManager.loadTPAddItem = function(){
	for(var i = 1; i < $dataItems.length; i++){
		var item = $dataItems[i];
		item.tpParamPlus = 0;
		item.tpParamPlusEval = null;

		if(item.meta["Add TP Param"]){
			var add = Number(item.meta["Add TP Param"]) || 0;
			item.tpParamPlus = add;
		}

		if(item.meta["Add TP Param Eval"]){
			var reg = /<Add TP Param Eval>([\s\S]*)<\/Add TP Param Eval>/;
			reg.exec(item.note);
			item.tpParamPlusEval = RegExp.$1;
		}
	}
};

CP.TPManager.loadTPItemReverse = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.tpReverseRate = 0;
		if(item.meta["TP Reverse Rate"])
			item.tpReverseRate = Number(item.meta["TP Reverse Rate"]) || 0;
	}
};

CP.TPManager.loadTPCostRate = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.tpCostRate = 1;
		item.tpCostRateEval = null;

		if(item.meta["TP Cost Rate"]){
			var rate = Number(item.meta["TP Cost Rate"]) || 0;
			item.tpCostRate = rate;
		}

		if(item.meta["TP Cost Rate Eval"]){
			var reg = /<TP Cost Rate Eval>([\s\S]*)<\/TP Cost Rate Eval>/;
			reg.exec(item.note);
			item.tpCostRateEval = RegExp.$1;
		}
	}
};

//旧档部分
CP.TPManager.EXTRACT_SAVE_CONTENTS = DataManager.extractSaveContents;
DataManager.extractSaveContents = function(contents){
	CP.TPManager.EXTRACT_SAVE_CONTENTS.call(this, contents);
	$gameActors.initWrongTpPlus();
};

Game_Actors.prototype.initWrongTpPlus = function(){
	for(var i = 0; i < this._data.length; i++){
		var actor = this._data[i];
		if(!!actor)
			actor.initBattlerTpPlus();
	}
};

//基础数据
CP.TPManager.INIT_MEMBERS = Game_BattlerBase.prototype.initMembers;
Game_BattlerBase.prototype.initMembers = function() {
   CP.TPManager.INIT_MEMBERS.call(this);

   this.initBattlerTpPlus();
};

//初始化，配合适配旧档
Game_BattlerBase.prototype.initBattlerTpPlus = function(){
	if(!this._tpPlus)
		this._tpPlus = 0;//体力上限永久提升值	
};

//额外体力值
Game_Battler.prototype.tpRateFromItem = function(item){
	var rate = 1;
	if(!item) return rate;

	rate = item.tpRate;

	if(item.tpRateEval){
		var user = this;

		try{
			eval(item.tpRateEval);
		}catch(err){
			rate = 1;
			console.error(err);
		}
	}

	return rate;
};

Game_Battler.prototype.tpPlusFromItem = function(item){
	var plus = 0;
	if(!item) return plus;

	plus = item.tpPlus;

	if(item.tpPlusEval){
		var user = this;

		try{
			eval(item.tpPlusEval);
		}catch(err){
			plus = 0;
			console.error(err);
		}
	}

	return plus;
};

Game_Battler.prototype.tpRateFromStates = function(){
	var rate = 1;
	var states = this.states();
	for(var i = 0; i < states.length; i++){
		rate *= this.tpRateFromItem(states[i]);
	}

	return rate;
};

Game_Battler.prototype.tpPlusFromStates = function(){
	var plus = 0;
	var states = this.states();
	for(var i = 0; i < states.length; i++){
		plus += this.tpPlusFromItem(states[i]);
	}

	return plus;
};

Game_Actor.prototype.tpRateFromEquips = function(){
	var rate = 1;
	var equips = this.equips();
	for(var i = 0; i < equips.length; i++){
		rate *= this.tpRateFromItem(equips[i]);
	}

	return rate;
};

Game_Actor.prototype.tpPlusFromEquips = function(){
	var plus = 0;
	var equips = this.equips();
	for(var i = 0; i < equips.length; i++){
		plus += this.tpPlusFromItem(equips[i]);
	}

	return plus;
};

Game_Actor.prototype.baseTPRate = function(){
	return this.tpRateFromItem(this.actor()) * this.tpRateFromItem(this.currentClass())
		 * this.tpRateFromEquips() * this.tpRateFromStates();
};

Game_Actor.prototype.baseTPPlus = function(){
	return this._tpPlus + this.tpPlusFromItem(this.actor()) + this.tpPlusFromItem(this.currentClass()) 
		+ this.tpPlusFromEquips() + this.tpPlusFromStates();
};

Game_Enemy.prototype.baseTPRate = function(){
	return this.tpRateFromItem(this.enemy()) * this.tpRateFromStates();
};

Game_Enemy.prototype.baseTPPlus = function(){
	return this.tpPlusFromItem(this.enemy()) + this.tpPlusFromStates();
};

CP.TPManager.CHANGE_TP_BY_DAMAGE = Game_Battler.prototype.chargeTpByDamage;
Game_Battler.prototype.chargeTpByDamage = function(damageRate){
	if(CP.TPManager.GAIN_TP_FROM_DAMAGE)
		CP.TPManager.CHANGE_TP_BY_DAMAGE.call(this, damageRate);
};

CP.TPManager.IS_PRESERVE_TP = Game_BattlerBase.prototype.isPreserveTp;
Game_BattlerBase.prototype.isPreserveTp = function(){
	if(CP.TPManager.TP_PRESERVED || CP.TPManager.TP_DEFAULT_ALL)
		return true;
	else
		return CP.TPManager.IS_PRESERVE_TP.call(this);
};

Game_Battler.prototype.initTp = function(){
	var value = 0;
	try{
		value = Math.round(eval(CP.TPManager.INIT_TP_FORMULA));
	}catch(err){
		value = Math.randomInt(Math.round(this.maxTp() / 4));
		console.error(err);
	}
	var value = Math.round(this.maxTp() / 4);
	this.setTp(value);
};

Game_Actor.prototype.maxTpBase = function() {
    var tp = CP.TPManager.DEFAULT_MAX_TP_VALUE;
    var ctp = this.currentClass().tpValue;
    var atp = this.actor().tpValue;

    var formula = this.currentClass().tpFormula || this.actor().tpFormula || CP.TPManager.DEFAULT_MAX_TP_FORMULA;
    if(formula == CP.TPManager.DEFAULT_MAX_TP_FORMULA){
    	if(ctp > 0)
    		return ctp;
    	else if(atp > 0)
    		return atp;
    }

	var user = this;
	
	try{
    	eval(formula);
    }catch(err){
    	tp = CP.TPManager.DEFAULT_MAX_TP_VALUE;
    	console.error(err);
    }

    return tp;
};	

Game_Enemy.prototype.maxTpBase = function() {
    var tp = CP.TPManager.DEFAULT_MAX_TP_VALUE;
    var etp = this.enemy().tpValue;

    var formula = this.enemy().tpFormula || CP.TPManager.DEFAULT_MAX_TP_FORMULA;
   
    if(formula == CP.TPManager.DEFAULT_MAX_TP_FORMULA){
    	if(etp > 0)
    		return etp;
    }

    var user = this;

	try{
    	eval(formula);
    }catch(err){
    	tp = CP.TPManager.DEFAULT_MAX_TP_VALUE;
    	console.error(err);
    }
     
    return tp;
};

Game_Battler.prototype.maxTp = function(){
	return Math.round((this.maxTpBase() + this.baseTPPlus()) * this.baseTPRate());
};

//恢复 添加部分
Game_Battler.prototype.regenerateTp = function(){
    var value = Math.floor(this.maxTp() * this.trg);
    this.gainTp(value);
};

CP.TPManager.RECOVER_ALL = Game_BattlerBase.prototype.recoverAll;
Game_BattlerBase.prototype.recoverAll = function() {
    CP.TPManager.RECOVER_ALL.call(this);
    if(CP.TPManager.TP_DEFAULT_ALL)
    	this._tp = this.maxTp();
};

Game_Actor.prototype.addTPParam = function(value){
	this._tpPlus += value;
};

//行动效果
CP.TPManager.INIT_ACTION = Game_Action.prototype.initialize;
Game_Action.prototype.initialize = function(subject, forcing){
	CP.TPManager.INIT_ACTION.call(this, subject, forcing);

	this._tpCriticalTest = false; //临时变量，判定是否计算tp暴击
};

Game_Action.prototype.isTpEffect = function(){
	var item = this.item();

	return item.tpRecover.value !== 0 || item.tpRecover.percent !== 0 || !!item.tpRecover.eval;
};

Game_Action.prototype.isTpDamage = function(){
	var item = this.item();

	return this.isTpEffect() && item.tpRecover.type === -1;
};

Game_Action.prototype.isTpRecover = function(){
	var item = this.item();

	return this.isTpEffect() && item.tpRecover.type === 1;
};

CP.TPManager.APPLY_ACTION = Game_Action.prototype.apply;
Game_Action.prototype.apply = function(target) {
	CP.TPManager.APPLY_ACTION.call(this, target);

    var item = this.item();
    if(item.tpParamPlus > 0 || item.tpParamPlusEval)
    	this.addTPParam(target);
};

//在命中的最后 执行TP操作
CP.TPManager.APPLY_ACTION_USER_EFFECT = Game_Action.prototype.applyItemUserEffect;
Game_Action.prototype.applyItemUserEffect = function(target) {
    CP.TPManager.APPLY_ACTION_USER_EFFECT.call(this, target);

    if(this.isTpEffect())
    	this.executeTpRecovery(target);
};

Game_Action.prototype.executeTpRecovery = function(target){
	 var result = target.result();
	 var item = this.item();
	 var variance = item.tpRecover.variance;
	 var critical = false;
	 var reverseRate = target.tpReverseRate();

	 var value = 0;
	 var user = this.subject();

	 try{
	 	if(item.tpRecover.eval)
	 		eval(item.tpRecover.eval);
	 	else
	 		value = item.tpRecover.percent * user.maxTp() + item.tpRecover.value;
	 }catch(err){
	 	value = item.tpRecover.percent * user.maxTp() + item.tpRecover.value;
	 	console.error(err);
	 }

	 if(value < 0)
	 	value = 0;

	 variance = variance.clamp(0, 100);
	 value = this.applyVariance(value, variance);

	 if(item.tpRecover.critical && Math.random() < this.tpCri(target)){
	 	value = this.applyCritical(value);
	 	target.result().tpCritical = true;
	 }

	 if(value > 0 && reverseRate > 0 && item.tpRecover.type > 0)
	 	value = value * (-reverseRate);

	 this.makeSuccess(target);
	 target.gainTp(Math.round(value * item.tpRecover.type));
};

//TP暴击部分
CP.TPManager.CLEAR_ACTION_RESULT = Game_ActionResult.prototype.clear;
Game_ActionResult.prototype.clear = function(){
	CP.TPManager.CLEAR_ACTION_RESULT.call(this);

	this.tpCritical = false; //独立出TP暴击
};

CP.TPManager.ACTION_ITEM_CRI = Game_Action.prototype.itemCri;
Game_Action.prototype.itemCri = function(target){
	if(!this._tpCriticalTest)
		return CP.TPManager.ACTION_ITEM_CRI.call(this, target);

	var item = this.item();
	var critical = item.damage.critical;
	item.damage.critical = item.tpRecover.critical;

	var rate = CP.TPManager.ACTION_ITEM_CRI.call(this, target);
	item.damage.critical = critical;

	return rate;
};

Game_Action.prototype.tpCri = function(target){
	this._tpCriticalTest = true;
	var rate = this.itemCri(target);
	this._tpCriticalTest = false;

	return rate;
};

//TP逆转效果部分
Game_Battler.prototype.tpReverseRate = function(){
	return this.tpReverseRateForStates();
};

Game_Battler.prototype.tpReverseRateForItem = function(item){
	if(!item)
		return 0;
	var value = item.tpReverseRate || 0;
	if(value < 0)
		value = 0;
	return value;
};

Game_Battler.prototype.tpReverseRateForStates = function(){
	var value = 0;
	var states = this.states();
	for(var i = 0; i < states.length; i++)
		value += this.tpReverseRateForItem(states[i]);
	return value;
};

Game_Actor.prototype.tpReverseRate = function(){
	return Game_Battler.prototype.tpReverseRate.call(this) + this.tpReverseRateForItem(this.actor())
		+ this.tpReverseRateForItem(this.currentClass()) + this.tpReverseRateForEquips();
};

Game_Actor.prototype.tpReverseRateForEquips = function(){
	var value = 0;
	var equips = this.equips();
	for(var i = 0; i < equips.length; i++)
		value += this.tpReverseRateForItem(equips[i]);
	return value;
};

Game_Enemy.prototype.tpReverseRate = function(){
	return Game_Battler.prototype.tpReverseRate.call(this) + this.tpReverseRateForItem(this.enemy());
};

//上限部分
Game_Action.prototype.addTPParam = function(target){
	var item = this.item();
	var plus = 0;

	if(item.tpParamPlus > 0)
		plus = item.tpParamPlus;
	else if(item.tpParamPlusEval){
		var user = this.subject();
		try{
			eval(item.tpParamPlusEval);
		}catch(err){
			plus = 0;
			console.error(err);
		}
	}

	target.addTPParam(plus);
};

//战斗外体力恢复允许使用
//体力上限物品允许使用
CP.TPManager.HAS_ITEM_ANY_VALID_EFFECT = Game_Action.prototype.hasItemAnyValidEffects;
Game_Action.prototype.hasItemAnyValidEffects = function(target) {
	var result = CP.TPManager.HAS_ITEM_ANY_VALID_EFFECT.call(this, target);
	if(!!result)
		return true;
	
	var item = this.item();
	if(this.isTpEffect()){
		if(this.isTpRecover() && target.tp === target.maxTp())
			result = false;
		else
			result = true;
	}
	if(item.tpParamPlus > 0 || item.tpParamPlusEval)
		result = true;
    return result;
};

//TP消耗部分
Game_Battler.prototype.tpCostRateFromItem = function(item){
	var rate = 1;
	if(!item) return rate;

	rate = item.tpCostRate;

	if(item.tpCostRateEval){
		var user = this;

		try{
			eval(item.tpCostRateEval);
		}catch(err){
			rate = 1;
			console.error(err);
		}
	}

	return rate;
};

Game_Battler.prototype.tpCostRateFromStates = function(){
	var rate = 1;
	var states = this.states();
	for(var i = 0; i < states.length; i++){
		rate *= this.tpCostRateFromItem(states[i]);
	}

	return rate;
};

Game_Actor.prototype.tpCostRateFromEquips = function(){
	var rate = 1;
	var equips = this.equips();
	for(var i = 0; i < equips.length; i++){
		rate *= this.tpCostRateFromItem(equips[i]);
	}

	return rate;
};

Game_Actor.prototype.tpCostRate = function(){
	return this.tpCostRateFromItem(this.actor()) * this.tpCostRateFromItem(this.currentClass()) * this.tpCostRateFromEquips() 
		* this.tpCostRateFromStates();
};


Game_Enemy.prototype.tpCostRate = function(){
	return this.tpCostRateFromItem(this.enemy()) * this.tpCostRateFromStates();
};

Game_Battler.prototype.skillTpCost = function(skill) {
    var cost = Math.round(Game_BattlerBase.prototype.skillTpCost.call(this, skill) * this.tpCostRate());

    return cost > 0 ? cost : 0;
};

//伤害弹出部分
//构造数字
CP.TPManager.SETUP_DAMAGE_SPRITE = Sprite_Damage.prototype.setup;
Sprite_Damage.prototype.setup = function(target) {
	CP.TPManager.SETUP_DAMAGE_SPRITE.call(this, target);

	var result = target.result();
	if(Imported.YEP_BattleEngineCore)
		result = this._result;

   if(!result.missed && !result.evaded && target.isAlive() && result.tpDamage !== 0)
        this.createDigits(CP.TPManager.TP_POPUP_BASE_LINE, result.tpDamage);

    if (result.tpDamage !== 0 && result.tpCritical)
        this.setupCriticalEffect();
};

Sprite_Damage.prototype.digitHeight = function() {
    return this._damageBitmap ? this._damageBitmap.height / CP.TPManager.DAMAGE_IMAGE_LINES : 0;
};

CP.TPManager.BATTLER_START_DAMAGE_POPUP = Game_Battler.prototype.startDamagePopup;
Game_Battler.prototype.startDamagePopup = function() {
	if(Imported.YEP_BattleEngineCore)
		this.startDamagePopupForYEPBattle();
	else
		CP.TPManager.BATTLER_START_DAMAGE_POPUP.call(this);
};

Game_Battler.prototype.startDamagePopupForYEPBattle = function() {
	var result = this.result();
    if(result.missed || result.evaded) {
	    var copyResult = JsonEx.makeDeepCopy(result);
	    copyResult.hpAffected = false;
	    copyResult.mpDamage = 0;
	    copyResult.tpDamage = 0;
	    this._damagePopup.push(copyResult);
    }
    if (result.hpAffected) {
	    var copyResult = JsonEx.makeDeepCopy(result);
	    copyResult.mpDamage = 0;
	    copyResult.tpDamage = 0;
	    this._damagePopup.push(copyResult);
    }
    if (result.mpDamage !== 0) {
	    var copyResult = JsonEx.makeDeepCopy(result);
	    copyResult.hpAffected = false;
	    copyResult.tpDamage = 0;
	    this._damagePopup.push(copyResult);
    }
    if(result.tpDamage != 0){
 	    var copyResult = JsonEx.makeDeepCopy(result);
	    copyResult.hpAffected = false;
	    copyResult.mpDamage = 0;
	    this._damagePopup.push(copyResult);
	}
};

CP.TPManager.PLUGIN_COMMAND = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
	CP.TPManager.PLUGIN_COMMAND.call(this, command, args);

	if(command == 'ChangeMaxTp'){
		var actorId = Number(args[0]) || 0;
		var value = Number(args[1]) || 0;
		
		var actor = $gameActors.actor(actorId);
		if(actor)
			actor.addTPParam(value);
	}
};